﻿using Kvaser.CanLib;
using ScottPlot.Drawing.Colormaps;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using XH.BMS.Base;
using XH.BMS.DAL;
using XH.BMS.Entity;
using XH.BMS.Models;

namespace XH.BMS.ViewModels
{
    public class MainViewModel : NotifyBase
    {
        CancellationTokenSource cts = new CancellationTokenSource();
        // 线程安全队列
        ConcurrentQueue<ValueEntity> Values = new ConcurrentQueue<ValueEntity>();

        #region Monitor页面的数据
        public MonitorModel MonitorPageModel { get; set; } = new MonitorModel();
        public List<ConditionItemModel> MonitorConditions { get; set; } = new List<ConditionItemModel>();
        #endregion

        #region 趋势图表页面的数据
        #endregion

        // 呈现页面对象   ，之前是页面地址（不使用）
        private object _pageObject;
        public object PageObject
        {
            get { return _pageObject; }
            set { SetProperty(ref _pageObject, value); }
        }


        public Command NavCommand { get; set; }
        private bool _navState;
        public bool NavState
        {
            get { return _navState; }
            set { SetProperty(ref _navState, value); }
        }
        LocalDataAccess LocalDataAccess = new LocalDataAccess();

        public MainViewModel()
        {
            NavCommand = new Command(SwitchPage);
            this.SwitchPage("MonitorPage");

            // 初始化电池信息
            Refresh();
            // 监控CAN报文
            Monitor();

        }

        private List<Task> ts = new List<Task>();
        int canHandle = 0;
        public void Dispose()
        {
            // 线程销毁
            cts.Cancel();
            Task.WaitAll(ts.ToArray());

            // 关装Kvaser CAN接口
            Canlib.canBusOff(canHandle);
            Canlib.canClose(canHandle);
        }

        private void SwitchPage(object page)
        {
            string pageName = page.ToString();
            if (pageName.StartsWith("to"))
            {
                pageName = pageName.Split(":")[1];
                // 区分出特殊跳转页面
                NavState = true;
                // 如果是TabControl  处理不同    SelectedIndex =“Binding Index”  Index=2
            }
            Type type = Assembly.GetExecutingAssembly().GetType("XH.BMS.Views.Pages." + pageName);
            this.PageObject = Activator.CreateInstance(type);
        }

        private void Refresh()
        {
            DataTable dt = LocalDataAccess.GetBatteryGroup();

            foreach (var item in dt.AsEnumerable())
            {
                GroupItemModel gm = new GroupItemModel();
                gm.CANID = item["can_id"].ToString();
                gm.Header = item["header"].ToString();
                int cc = int.Parse(item["cell_count"].ToString());
                for (int i = 0; i < cc; i++)
                {
                    gm.Cells.Add(new CellModel
                    {
                        Id = i + 1
                    });
                }

                MonitorPageModel.BatteryGroup.Add(gm);
            }

            // 初始化获取相关配置
            dt = LocalDataAccess.GetNormalSettings();

            foreach (var item in dt.AsEnumerable())
            {
                var v1 = item.Field<string>("p_value_1");
                var v2 = item.Field<string>("p_value_2");
                var v3 = item.Field<string>("p_value_3");
                var v4 = item.Field<string>("p_value_4");
                MonitorConditions.Add(new ConditionItemModel
                {
                    CName = item["p_name"].ToString()!,

                    PValue1 = v1 != null ? double.Parse(v1.ToString()!) : 0.0,
                    PValue2 = v2 != null ? double.Parse(v2.ToString()!) : 0.0,
                    PValue3 = v3 != null ? double.Parse(v3.ToString()!) : 0.0,
                    PValue4 = v4 != null ? double.Parse(v4.ToString()!) : 0.0
                });
            }

            dt = LocalDataAccess.GetAlarmsUnchecked();
            foreach (var item in dt.AsEnumerable())
            {
                AlarmItemModel am = new AlarmItemModel();
                am.Title = item["title"].ToString();
                am.Description = item["desc"].ToString();
                am.Date = item["date"].ToString();
                am.AlarmType = item["a_type"].ToString();
                am.Name = item["name"].ToString();

                MonitorPageModel.BatteryMessage.Add(am);
            }
        }

        private void Monitor()
        {
            // CAN模块初始化
            Canlib.canInitializeLibrary();

            // 打开通道
            canHandle = Canlib.canOpenChannel(1, Canlib.canOPEN_ACCEPT_VIRTUAL);
            // 可选动作：设置波特率
            Canlib.canSetBitrate(canHandle, Canlib.canBITRATE_500K);
            // 打开总线
            Canlib.canBusOn(canHandle);

            // 电池模块总体信息
            var t = Task.Run(async () =>
            {
                while (!cts.IsCancellationRequested)
                {
                    await Task.Delay(1000);
                    byte[] datas = new byte[8];
                    var state = Canlib.canReadSpecific(canHandle, 0x1806E1F4, datas, out int dlc, out int flag, out long time);
                    // 8个字节中：第一个SOC    第二个SOH   第三、四个电压   5、6电流    7、8电量   按大端处理
                    if (state == Canlib.canStatus.canOK)
                    {
                        MonitorPageModel.SoC = datas[0];
                        Values.Enqueue(new ValueEntity { Name = "整体模块SoC", Value = datas[0].ToString() });
                        MonitorPageModel.SoH = datas[1];
                        Values.Enqueue(new ValueEntity { Name = "整体模块SoH", Value = datas[1].ToString() });
                        MonitorPageModel.Voltage = BitConverter.ToUInt16(new byte[] { datas[3], datas[2] });
                        Valid("总电压", MonitorPageModel.Voltage);

                        MonitorPageModel.Current = BitConverter.ToUInt16(new byte[] { datas[5], datas[4] });
                    }
                }
            }, cts.Token);
            ts.Add(t);
            // 各电池组信息
            for (int i = 0; i < MonitorPageModel.BatteryGroup.Count; i++)
            {
                int index = i;
                t = Task.Run(async () =>
                {
                    Dictionary<int, byte[]> byteDic = new Dictionary<int, byte[]>();
                    int p_index = 1;
                    while (!cts.IsCancellationRequested)
                    {
                        await Task.Delay(100);
                        byte[] datas = new byte[8];
                        List<byte> idBytes = new List<byte>(Convert.FromHexString(MonitorPageModel.BatteryGroup[index].CANID));
                        idBytes.Reverse();
                        int can_id = BitConverter.ToInt32(idBytes.ToArray());
                        var state = Canlib.canReadSpecific(canHandle, can_id, datas, out int dlc, out int flag, out long time);
                        //Debug.WriteLine(string.Join(" ",datas.sele))
                        if (state != Canlib.canStatus.canOK) continue;
                        // 必须先添加1  再添加2
                        if (p_index == datas[0] && !byteDic.ContainsKey(datas[0]))
                        {
                            byteDic.Add(datas[0], datas);
                            p_index++;
                        }
                        if (byteDic.Count == 4)
                        {
                            // 数据解析
                            List<byte> dataBytes = new List<byte>();
                            dataBytes.AddRange(new List<byte>(byteDic[1]).GetRange(1, 7));
                            dataBytes.AddRange(new List<byte>(byteDic[2]).GetRange(1, 7));
                            dataBytes.AddRange(new List<byte>(byteDic[3]).GetRange(1, 7));
                            dataBytes.AddRange(new List<byte>(byteDic[4]).GetRange(1, 7));

                            // 组电量
                            var v = BitConverter.ToUInt16(new byte[] { dataBytes[1], dataBytes[0] });
                            MonitorPageModel.BatteryGroup[index].Capacitance = v;
                            // 组温度
                            v = BitConverter.ToUInt16(new byte[] { dataBytes[3], dataBytes[2] });
                            MonitorPageModel.BatteryGroup[index].Temperature = v;

                            int cell_index = 0;
                            for (int i = 4; i < dataBytes.Count; i += 2)
                            {
                                v = BitConverter.ToUInt16(new byte[] { dataBytes[i + 1], dataBytes[i] });
                                MonitorPageModel.BatteryGroup[index].Cells[cell_index].Voltage = v;
                                cell_index++;

                                Values.Enqueue(new ValueEntity { Name = $"{MonitorPageModel.BatteryGroup[index].Header}.Cells[{cell_index}]电压", Value = v.ToString() });
                            }

                            byteDic.Clear();
                            p_index = 1;
                        }
                    }
                }, cts.Token);
                ts.Add(t);
            }


            t = Task.Run(async () =>
            {
                List<ValueEntity> updateDatas = new List<ValueEntity>();
                while (!cts.IsCancellationRequested)
                {
                    // 每次从数据保存的缓存队列中取出一个有效信息
                    // TryDequeue 方法每次从队列中取一个记录并清除此记录
                    bool state = Values.TryDequeue(out ValueEntity value);
                    if (state)
                    {
                        // 添加到临时队列
                        updateDatas.Add(value);
                        if (updateDatas.Count == 10)
                        {
                            // 调用保存
                            LocalDataAccess.SaveValues(updateDatas);
                            updateDatas.Clear();
                        }
                    }
                    else
                    {
                        await Task.Delay(100);
                    }
                }
            }, cts.Token);
            ts.Add(t);
        }

        private void Valid(string name, double value)
        {
            // 条件集合
            var mc = MonitorConditions.FirstOrDefault(m => m.CName == name);
            if (mc != null)
            {
                var exsit = MonitorPageModel.BatteryMessage.ToList().Exists(bm => bm.Name == name);
                if (exsit)
                {
                    if (value <= mc.PValue1 && value >= mc.PValue2)// 正常的条件下，之前已有的报警移除
                        MonitorPageModel.BatteryMessage.ToList().RemoveAll(bm => bm.Name == name);
                }
                else// 不存在当前名称的消息    假如报警的过程  问题处理了   当前这条记录需要清除
                {
                    AlarmItemModel aim = null;
                    if (value > mc.PValue1)
                    {
                        aim = new AlarmItemModel
                        {
                            Name = name,
                            Title = $"{name}上限预警",
                            Description = $"{name}超出上限[{mc.PValue1}]要求",
                            Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                            AlarmType = "紧急"
                        };
                    }
                    else if (value < mc.PValue2)
                    {
                        aim = new AlarmItemModel
                        {
                            Name = name,
                            Title = $"{name}下限预警",
                            Description = $"{name}低于下限[{mc.PValue2}]要求",
                            Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                            AlarmType = "紧急"
                        };
                    }

                    if (aim != null)
                    {
                        Application.Current.Dispatcher.Invoke(() =>
                        {
                            MonitorPageModel.BatteryMessage.Add(aim);
                        });
                        // 此处做存库操作
                        LocalDataAccess.SaveAlarm(new AlarmEntity
                        {
                            Title = aim.Title,
                            Description = aim.Description,
                            Date = aim.Date,
                            AlarmType = aim.AlarmType,
                            Name = aim.Name
                        });
                    }
                }
            }
        }
    }
}
